﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace JESAI.Redis.Internal.ObjectPool
{
    /// <summary>
    /// 默认的对象池策略
    /// </summary>
    public class DefaultPolicy<T> : IPolicy<T>
    {
        #region 回调函数
        /// <summary>
        /// 对象创建函数
        /// </summary>
        public Func<T> CreateObjectFunc;

        /// <summary>
        /// 获取对象回调函数
        /// </summary>
        public Action<Object<T>> OnGetObject;

        /// <summary>
        /// 对象销毁回调函数
        /// </summary>
        public Action<T> OnDestroyObject;

        /// <summary>
        /// 从对象池获取对象超时的时候触发
        /// </summary>
        public Action OnGetObjectTimeout;

        /// <summary>
        /// 归还对象回调
        /// </summary>
        public Action<Object<T>> OnReturnObject;

        /// <summary>
        /// 后台定时检查可用性回调
        /// </summary>
        public Action<Object<T>> OnCheckObjectAvailable;

        /// <summary>
        /// 对象可用时触发
        /// </summary>
        public Action OnObjectAvailable;

        /// <summary>
        /// 对象不可用时触发
        /// </summary>
        public Action OnObjectUnavailable;
        #endregion

        /// <summary>
        /// 对象池名称
        /// </summary>
        public string Name { get; set; } = "DefaultObjectPoolPolicy";

        /// <summary>
        /// 对象池最大容量
        /// </summary>
        public int MaxPoolSize { get; set; } = 2000;

        /// <summary>
        /// 获取超时设置
        /// </summary>
        public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(30);

        /// <summary>
        /// 空闲对象回收时间
        /// </summary>
        public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(50);

        /// <summary>
        /// 异步获取排队队列大小，小于等于0不生效
        /// </summary>
        public int AsyncGetCapacity { get; set; } = 10000;

        /// <summary>
        /// 获取超时后，是否抛出异常
        /// </summary>
        public bool IsThrowGetTimeoutException { get; set; } = true;

        /// <summary>
        /// 监听 AppDomain.CurrentDomain.ProcessExit/Console.CancelKeyPress 事件自动释放
        /// </summary>
        public bool IsAutoDisposeWithSystem { get; set; } = true;


        /// <summary>
        /// 后台定时检查可用性间隔秒数
        /// </summary>
        public int CheckAvailableInterval { get; set; } = 3;

        /// <summary>
        /// 对象池的对象被创建时
        /// </summary>
        /// <returns>返回被创建的对象</returns>
        public T OnCreate()
        {
            if (CreateObjectFunc != null)
            {
                return CreateObjectFunc();
            }

            return default(T);
        }

        /// <summary>
        /// 销毁对象
        /// </summary>
        /// <param name="obj">资源对象</param>
        public void OnDestroy(T obj)
        {
            OnDestroyObject?.Invoke(obj);
        }


        /// <summary>
        /// 从对象池获取对象超时的时候触发，通过该方法统计
        /// </summary>
        public void OnGetTimeout()
        {
            OnGetObjectTimeout?.Invoke();
        }

        /// <summary>
        /// 从对象池获取对象成功的时候触发，通过该方法统计或初始化对象
        /// </summary>
        /// <param name="obj">资源对象</param>
        public void OnGet(Object<T> obj)
        {
            OnGetObject?.Invoke(obj);
        }

#if net40
#else
        /// <summary>
        /// 从对象池获取对象成功的时候触发，通过该方法统计或初始化对象
        /// </summary>
        /// <param name="obj">资源对象</param>
        public async Task OnGetAsync(Object<T> obj)
        {
            OnGetObject?.Invoke(obj);
        }

#endif

        /// <summary>
        /// 归还对象给对象池的时候触发
        /// </summary>
        /// <param name="obj">资源对象</param>
        public void OnReturn(Object<T> obj)
        {
            OnReturnObject?.Invoke(obj);
        }

        /// <summary>
        /// 检查可用性
        /// </summary>
        /// <param name="obj">资源对象</param>
        /// <returns></returns>
        public bool OnCheckAvailable(Object<T> obj)
        {
            OnCheckObjectAvailable?.Invoke(obj);
            return true;
        }

        /// <summary>
        /// 事件：可用时触发
        /// </summary>
        public void OnAvailable()
        {
            OnObjectAvailable?.Invoke();
        }

        /// <summary>
        /// 事件：不可用时触发
        /// </summary>
        public void OnUnavailable()
        {
            OnObjectUnavailable?.Invoke();
        }
    }
}
